﻿//Released to the public domain.
//  Carl Kadie, carlk@msn.com
//  http://slugco.com


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sony.Vegas;
using System.Web;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;


namespace Dawf
{
    public class EntryPoint
    {
        public void FromVegas(Vegas vegas)
        {
            try
            {
                int tracksChanged = 0;
                foreach (AudioEvent badAudioEvent in BadAudioSequence(vegas))
                {
                    if (TryReplaceAudio(badAudioEvent, vegas))
                    {
                        ++tracksChanged;
                    }
                }
                vegas.UpdateUI();
                MessageBox.Show(string.Format("Dawf changed {0} track events", tracksChanged));
            }
            catch(Exception exception)
            {
                MessageBox.Show("Error: " + exception.Message);
            }

        }

        private bool TryReplaceAudio(AudioEvent badAudioEvent, Vegas vegas)
        {
            AudioEvent goodAudioEvent;
            if (!TryFindNewAudio(vegas, badAudioEvent, out goodAudioEvent))
            {
                return false;
            }

            //Copy a piece of the new audio up to this track and trim it to match the old audio
            TrackEvent copy = goodAudioEvent.Copy(badAudioEvent.Track, goodAudioEvent.Start);
            copy.AdjustStartLength(badAudioEvent.Start, badAudioEvent.Length, /*adjustTakes*/ true); //!!!what does adjustTakes do?

            //copy the group and original position over
            badAudioEvent.Group.Add(copy);
            badAudioEvent.Group.Remove(badAudioEvent);

            //Remove the old audio
            badAudioEvent.Track.Events.Remove(badAudioEvent);
            return true;
        }

        private bool TryFindNewAudio(Vegas vegas, TrackEvent badAudioEvent, out AudioEvent goodAudioEvent)
        {
            goodAudioEvent = null;
            foreach (Track goodAudioTrack in vegas.Project.Tracks)
            {
                if (goodAudioTrack.IsAudio() && goodAudioTrack != badAudioEvent.Track)
                {
                    foreach (AudioEvent audioEvent in goodAudioTrack.Events)
                    {
                        if (!audioEvent.IsGrouped)
                        {
                            if (audioEvent.Start <= badAudioEvent.Start && badAudioEvent.End <= audioEvent.End)
                            {
                                if (goodAudioEvent != null) throw new Exception("Two or more good audio clips seem to overlap.");
                                goodAudioEvent = audioEvent;
                            }
                        }
                    }
                }
            }
            return goodAudioEvent != null;
        }


        /// <summary>
        /// Returns all selected bad audio tracks. If, however, there are none, it returns the nonselected bad audio tracks.
        /// </summary>
        private IEnumerable<AudioEvent> BadAudioSequence(Vegas vegas)
        {
            var selectedBadAudioList = BadAudioSequence(/*isSelected*/ true, vegas).ToList();
            if (selectedBadAudioList.Count > 0)
            {
                return selectedBadAudioList;
            }
            else
            {
                return BadAudioSequence(/*isSelected*/ false, vegas);
            }
        }

        private IEnumerable<AudioEvent> BadAudioSequence(bool isSelected, Vegas vegas)
        {

            foreach (Track track in vegas.Project.Tracks)
            {
                if (track.IsAudio())
                {
                    foreach (AudioEvent badAudioEvent in track.Events)
                    {
                        VideoEvent badVideoEvent;
                        if (IsBadAudioEvent(badAudioEvent, vegas, out badVideoEvent) && (badAudioEvent.Selected == isSelected || badVideoEvent.Selected == isSelected)) 
                        {
                            yield return badAudioEvent;
                        }
                    }
                }
            }

        }


        private static bool TrackContainsBadAudio(Track track, Vegas vegas)
        {
            Debug.Assert(track.IsAudio());
            foreach (AudioEvent audioTrackEvent in track.Events)
            {
                VideoEvent badVideoEvent;
                if (IsBadAudioEvent(audioTrackEvent, vegas, out badVideoEvent))
                {
                    return true;
                }
            }
            return false;
        }

        private static bool IsBadAudioEvent(AudioEvent audioTrackEvent, Vegas vegas, out VideoEvent badVideoEvent)
        {
            badVideoEvent = null;
            if (!audioTrackEvent.IsGrouped)
            {
                return false;
            }
            TrackEventGroup trackEventGroup = audioTrackEvent.Group;
            if (trackEventGroup.Count != 2)
            {
                return false;
            }
            Media media = GetMedia(audioTrackEvent);
            foreach (TrackEvent trackEvent in trackEventGroup.Where(trackEvent => trackEvent != audioTrackEvent))
            {
                if (!trackEvent.IsVideo() || media.MediaID != GetMedia(trackEvent).MediaID)
                {
                    return false;
                }
                badVideoEvent = (VideoEvent) trackEvent;
            }
            return true;

        }

        private static Media GetMedia(TrackEvent trackEvent)
        {
            return trackEvent.Takes[0].Media;
        }

    }
}

